﻿using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Microsoft.EntityFrameworkCore;
using Mt.Site.Application.Dto;
using Mt.Site.Application.Editions.Dto;
using Mt.Site.Application.Modules.Dto;
using Mt.Site.Core.Navigations.Entities;
using Mt.Site.Core.Navigations.Modules;
using Mt.Site.Core.Navigations.Permissions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;

namespace Mt.Site.Application.Modules
{
    [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage)]
    public class ModuleAppService : MtSiteAppServiceBase, IModuleAppService
    {
        private readonly IModuleManager _moduleManager;
        private readonly IRepository<BackEndModule, Guid> _backEndModuleRepository;
        private readonly IModuleProvider _moduleProvider;

        public ModuleAppService(
            IModuleManager moduleManager,
            IRepository<BackEndModule, Guid> backEndModuleRepository,
            IModuleProvider moduleProvider)
        {
            _moduleManager = moduleManager;
            _backEndModuleRepository = backEndModuleRepository;
            _moduleProvider = moduleProvider;
        }

        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_Create)]
        public async Task CreateAsync(CreateModuleDto input)
        {
            using (CurrentUnitOfWork.SetTenantId(null))
            {
                var m = ObjectMapper.Map<BackEndModule>(input);
                m.Order = await _moduleManager.GetMaxOrder();

                await _moduleManager.CreateAsync(m);
            }
        }

        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_Create)]
        public async Task CopyNewOneAsync(EntityDto<Guid> input) 
        {
            await _moduleManager.CopyNewOne(input.Id);
        }

        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_Delete)]
        public async Task DeleteAsync(EntityDto<Guid> input)
        {
            using (CurrentUnitOfWork.SetTenantId(null))
            {
                await _moduleManager.DeleteAsync(input.Id);
            }
        }
        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_Delete)]
        public async Task DeleteListAsync(List<Guid> input)
        {
            using (CurrentUnitOfWork.SetTenantId(null))
            {
                await _moduleManager.DeleteListAsync(input);
            }
        }

        public async Task<GetModuleForEditOutput> GetAsync(NullableIdDto<Guid> input)
        {
            var features = FeatureManager.GetAll()
                .Where(
                c => {
                    var str = c.DefaultValue.ToLower();
                    if (str == "true" || str == "false")
                    {
                        return true;
                    }
                    return false;
                });

            ModuleDto moduleDto;
            List<string> featureValues ;

            using (CurrentUnitOfWork.SetTenantId(null))
            {
                if (input.Id.HasValue)
                {
                    var module = await _moduleManager.GetAsync(input.Id.Value);
                    moduleDto = ObjectMapper.Map<ModuleDto>(module);

                    var featuresParam = _moduleManager.GetModuleFeatures(module.Name);
                    moduleDto.RequiredFeatures = featuresParam.RequiredFeatures.ToList();
                    moduleDto.RequiresAll = featuresParam.RequiresAll;
                }
                else
                {
                    moduleDto = null;
                    featureValues = new List<string>();
                }
            }

            return new GetModuleForEditOutput
            {
                Module = moduleDto,
                Features = ObjectMapper.Map<List<FlatFeatureDto>>(features).OrderBy(f => f.DisplayName).ToList(),
                ModuleDefinitions = _moduleProvider.ModuleDefinitions.Select(c=>c.Value).OrderBy(f=>f.DisplayName).ToList()
            };
        }

        public async Task<PagedResultDto<PagedModuleDto>> GetPagedModules(PagedModuleInput input)
        {
            var query = _backEndModuleRepository.GetAll()
            .WhereIf(!input.Filter.IsNullOrEmpty(), t => t.DisplayName.Contains(input.Filter));

            query = !input.Sorting.IsNullOrEmpty() ? query.OrderBy(input.Sorting) : query.OrderByDescending(t => t.Order).ThenByDescending(t => t.CreationTime);

            var count = query.Count();
            var list = await query.PageBy(input).ToListAsync();
            return new PagedResultDto<PagedModuleDto>(count, ObjectMapper.Map<List<PagedModuleDto>>(list));
        }

        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_Edit)]
        public async Task SwapSortNumber(SwapSortNumberInput input)
        {
            var idList = input.IdOrderList.Select(c => c.Id).ToList();
            var orderList = input.IdOrderList.Select(c => c.Order).ToList();

            var list = await _backEndModuleRepository.GetAllListAsync(c => idList.Contains(c.Id));

            foreach (var item in list)
            {
                var index = idList.FindIndex(c=>c == item.Id);
                if(index != -1)
                {
                    item.Order = orderList[index];
                }
            }
        }

        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_Edit)]
        public async Task SetNewSorNumber(NewSortNumberInput input)
        {
            var ob = await _backEndModuleRepository.GetAsync(input.Id);
            ob.Order = input.NewNumber;
            await _backEndModuleRepository.UpdateAsync(ob);
        }


        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_Edit)]
        public async Task SetStatus(SetStatusInput input)
        {
            await _moduleManager.SetStatus(input.IdList, input.IsActive);
        }

        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_Edit)]
        public async Task UpdateAsync(UpdateModuleDto input)
        {
            var m = await _moduleManager.GetAsync(input.Id);
            AppCheck.CheckLastModificationTime(input.LastModificationTime, m, L("DataHasBeenChanged"));

            m.IsActive = input.IsActive;
            m.Name = input.Name;
            m.DisplayName = input.DisplayName;
            m.Description = input.Description;
            m.Icon = input.Icon;
            m.Url = input.Url;
            m.Target = input.Target;
            m.Order = input.Order;
            m.CustomData = input.CustomData;
            await _moduleManager.UpdateAsync(m);
        }

        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_FileEdit)]
        public async Task UpdateOrCreateConfigFileAsync(ConfigFileDto input)
        {
            await _moduleManager.UpdateOrCreateConfigFileAsync(input.Content);
        }
        [AbpAuthorize(MenuPermissions.Pages_Administration_BackendPage_FileEdit)]
        public async Task<string> GetConfigFileContentAsync()
        {
            return await _moduleManager.GetConfigFileContentAsync();
        }
    }
}
